/*
 * hdf5_parser.hpp
 *
 *  Created on: Aug 5, 2013
 *      Author: paste
 */

#ifndef HDF5_PARSER_HPP_
#define HDF5_PARSER_HPP_

#include <boost/property_tree/ptree.hpp>
#include "boost/property_tree/hdf5_parser_read.hpp"
#include "boost/property_tree/hdf5_parser_write.hpp"
#include "boost/property_tree/hdf5_parser_error.hpp"

#include <fstream>
#include <string>
#include <locale>

namespace boost {
namespace property_tree {
namespace hdf5_parser {

/**
 * Read HDF5 from a the given stream and translate it to a property tree.
 * @note Clears existing contents of property tree.  In case of error the
 *       property tree unmodified.
 * @note Items of HDF5 arrays are translated into ptree keys with multi_array
 *       values. Members of objects are translated into named keys.
 * @throw hdf5_parser_error In case of error deserializing the property
 *                          tree.
 * @param stream Stream from which to read in the property tree.
 * @param[out] pt The property tree to populate.
 */
template<class Ptree>
void read_hdf5(std::basic_istream<typename Ptree::key_type::value_type> &stream,
    Ptree &pt)
{
  read_hdf5_internal(stream, pt, std::string());
}

/**
 * Read HDF5 from a the given file and translate it to a property tree.
 * @note Clears existing contents of property tree.  In case of error the
 *       property tree unmodified.
 * @note Items of HDF5 arrays are translated into ptree keys with multi_array
 *       values. Members of objects are translated into named keys.
 * @throw hdf5_parser_error In case of error deserializing the property
 *                          tree.
 * @param filename Name of file from which to read in the property tree.
 * @param[out] pt The property tree to populate.
 * @param loc The locale to use when reading in the file contents.
 */
template<class Ptree>
void read_hdf5(const std::string &filename, Ptree &pt, const std::locale &loc =
    std::locale())
{
  std::basic_ifstream<typename Ptree::key_type::value_type> stream(
      filename.c_str());
  if (!stream)
    BOOST_PROPERTY_TREE_THROW(
        hdf5_parser_error("cannot open file", filename, 0));
  stream.imbue(loc);
  read_hdf5_internal(stream, pt, filename);
}

/**
 * Translates the property tree to HDF5 and writes it the given output
 * stream.
 * @throw hdf5_parser_error In case of error translating the property tree
 *                          to HDF5 or writing to the output stream.
 * @param stream The stream to which to write the HDF5 representation of the
 *               property tree.
 * @param pt The property tree to tranlsate to HDF5 and output.
 * @param matlab Whether or not to output a matlab-style .mat file.  defaults
 *               to false.
 */
template<class Ptree>
void write_hdf5(
    std::basic_ostream<typename Ptree::key_type::value_type> &stream,
    const Ptree &pt, bool matlab = false)
{
  write_hdf5_internal(stream, pt, std::string(), matlab);
}

/**
 * Translates the property tree to HDF5 and writes it the given file.
 * @throw hdf5_parser_error In case of error translating the property tree
 *                          to HDF5 or writing to the file.
 * @param filename The name of the file to which to write the HDF5
 *                 representation of the property tree.
 * @param pt The property tree to translate to HDF5 and output.
 * @param loc The locale to use when writing out to the output file.
 * @param matlab Whether or not to output a matlab-style .mat file.  defaults
 *               to false.
 */
template<class Ptree>
void write_hdf5(const std::string &filename, const Ptree &pt,
    const std::locale &loc = std::locale(), bool matlab = false)
{
  std::basic_ofstream<typename Ptree::key_type::value_type> stream(
      filename.c_str());
  if (!stream)
    BOOST_PROPERTY_TREE_THROW(
        hdf5_parser_error("cannot open file", filename, 0));
  stream.imbue(loc);
  write_hdf5_internal(stream, pt, filename, matlab);
}

} /* namespace hdf5_parser */
} /* namespace property_tree */
} /* namespace boost */

namespace boost {
namespace property_tree {
using hdf5_parser::read_hdf5;
using hdf5_parser::write_hdf5;
using hdf5_parser::hdf5_parser_error;
} /* namespace property_tree */
} /* namespace boost */

#endif /* HDF5_PARSER_HPP_ */
